package com.lottery.game.controller.v2.user;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lottery.game.annotation.Current;
import com.lottery.game.common.Response;
import com.lottery.game.common.constants.GameConstants;
import com.lottery.game.common.exception.BaseException;
import com.lottery.game.common.utils.DateUtils;
import com.lottery.game.common.utils.StringUtil;
import com.lottery.game.constants.RespErrorCodes;
import com.lottery.game.controller.v2.user.dto.userAccount.UpdateUserOnlineRequest;
import com.lottery.game.controller.v2.user.dto.userAccount.VerifyPayPwdRequest;
import com.lottery.game.controller.v2.user.dto.userAccount.WithdrawRequest;
import com.lottery.game.core.model.dto.UserToken;
import com.lottery.game.core.modules.entity.game.CheckResult;
import com.lottery.game.core.modules.entity.user.GameUser;
import com.lottery.game.core.modules.entity.user.GameUserAccount;
import com.lottery.game.core.modules.entity.user.GameUserAccountModel;
import com.lottery.game.core.modules.entity.user.UpAndDownReport;
import com.lottery.game.core.modules.service.app.*;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.extern.slf4j.Slf4j;
import springfox.documentation.annotations.ApiIgnore;

@Slf4j
@RestController
@RequestMapping(value = "api/v2/user/")
@Api(tags = "APP-用户账户相关接口")
public class UserAccountController {

    @Autowired
    private GameUserService gameUserService;

    @Autowired
    private GameUserAccountService gameUserAccountService;

    @Autowired
    private UpAndDownReportService upAndDownReportService;

    @Autowired
    private WebSocketService webSocketService;

    @Autowired
    private OnlineAppContext onlineAppContext;


    /**
     * 获取该用户绑定的银行
     *
     * @return
     */
    @SuppressWarnings("unchecked")
    @ApiOperation(value = "用户绑定的银行-ok", notes = "获取用户绑定的银行信息需要传递ticket", httpMethod = "GET")
    @ApiImplicitParam(name = "ticket", value = "ticket", dataType = "String", paramType = "header",required = true)
    @GetMapping(value = "/accounts", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public Response<List<GameUserAccount>> accounts(@ApiIgnore @Current UserToken ticket) {
        try {

            GameUserAccount gameUserAccount = new GameUserAccount();
            gameUserAccount.setAccountNo(ticket.getPhone());
            List<GameUserAccount> gameUserAccountList = gameUserAccountService.findList(gameUserAccount);
            if (gameUserAccountList.size() > 0) {
                return Response.build(gameUserAccountList);
            } else {
                return Response.buildError("该用户无绑定提现帐户");
            }
        } catch (Exception e) {
            throw new BaseException("查询失败，稍后再试");
        }
    }

    /**
     * 申请提现
     *
     * @param request
     * @return
     */
    @SuppressWarnings("unchecked")
    @ApiOperation(value = "申请提现", notes = "根据ticket申请个人提现(先调用'用户绑定的银行API获取到信息')", httpMethod = "POST")
    @ApiImplicitParam(name = "ticket", value = "ticket", dataType = "String", paramType = "header",required = true)
    @PostMapping(value = "/withdraw", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public Response<UpAndDownReport> withdraw(@ApiIgnore @Current UserToken userToken, @RequestBody WithdrawRequest request) {

        try {
            String bankId = request.getBankId();
            Double amount = request.getAmount();
            GameUser gameUser = gameUserService.get(userToken.getId());
            GameUserAccount gameUserAccount = gameUserAccountService.get(bankId);

            if (amount.doubleValue() > Double.parseDouble(gameUser.getBalance())) {
                return Response.buildError("提现失败，余额不足");
            } else {
                UpAndDownReport report = new UpAndDownReport();
                report.setApplyType("2");
                report.setStatus("0");
                report.setNickname(StringUtil.isEmpty(gameUser.getNickname())?"":gameUser.getNickname());
                report.setPayType(gameUserAccount.getAccountType());
                report.setApplyMoneyAmount(amount.toString());

                List<UpAndDownReport> list = upAndDownReportService.findList(report);
                //判断是否为空
                if (CollectionUtils.isEmpty(list)) {
                    CheckResult checkResult = gameUserAccountService.getDownCheck(gameUser, String.valueOf(amount));
                    if (checkResult.isSuccess()) {
                        //将其账户扣除金额，同时写一条账变记录
                        String reason = "用户发起提现申请,支付方式:" + gameUserAccount.getAccountType();
                        gameUserAccountService.updateGameBalane(gameUser, amount, reason);
                        UpAndDownReport upAndDownReport = new UpAndDownReport("2", "下分", new Date(), "0", "待审核", userToken.getId(), gameUser.getNickname(), gameUser.getPhotourl(), gameUser.getPhone(), gameUserAccount.getAccountType(), amount.toString());
                        upAndDownReport.setGameUserAccountId(bankId);
                        //如果提现了代理奖励佣金，则在remarks里存入提现的代理奖励佣金数值
                        if(org.apache.commons.lang3.StringUtils.equals("agent",checkResult.getMsg())){
                            String remarks = JSONObject.toJSONString(checkResult.getMap());
                            upAndDownReport.setRemarks(remarks);
                        }
                        upAndDownReportService.save(upAndDownReport);
                        //向管理后台推送下分WS消息
                        sendMessageSxfenCont();
                        return Response.buildSuccess(checkResult.getMsg());
                    }else {
                        return Response.buildError(checkResult.getMsg());
                    }

                } else {
                    return Response.buildError("正在处理中 请勿重复提交！");
                }
            }
        } catch (Exception e) {
            log.error(RespErrorCodes.UNKNOWN_ERROR.errorCode(), e);
            return Response.buildError("提现失败稍后再试");
        }

    }

    /**
     * 获取审核时间
     * TODO
     *
     * @param id 操作id
     * @return
     */
    @SuppressWarnings("unchecked")
    @ApiOperation(value = "审核时间", notes = "获取审核时间", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "ticket", value = "ticket", dataType = "String", paramType = "header",required = true),
            @ApiImplicitParam(name = "id", value = "id", dataType = "String",required = true)
    })

    @GetMapping(value = "/withdraw/show", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public Map<String, Object> getShow(@ApiIgnore @Current UserToken userToken, @RequestParam("id") String id) {

        Map<String, Object> map = new HashMap<>();
        try {
            UpAndDownReport upAndDownReport = upAndDownReportService.get(id);
            Date applyTime = upAndDownReport.getApplyTime();

            Calendar c = Calendar.getInstance();
            c.setTime(applyTime);
            c.add(Calendar.DAY_OF_MONTH, 2);// 今天+2天
            Date tomorrow = c.getTime();
            SimpleDateFormat dd = new SimpleDateFormat("MM月dd天");
            String format1 = dd.format(tomorrow);
            map.put("state", "1");
            map.put("a", DateUtils.parseDate(applyTime));
            map.put("b", format1);

            return map;
        } catch (Exception e) {
            log.error(RespErrorCodes.UNKNOWN_ERROR.errorCode(), e);
            throw new BaseException(RespErrorCodes.UNKNOWN_ERROR.getErrorMsg());
        }
    }

    /**
     * 根据手机号创建新账户
     * <p>
     * TODO: ??? 根据用户获取  该用户的上分下分机制  是否审核
     *
     * @param gameUserAccount
     * @return
     */
    @SuppressWarnings("unchecked")
    @ApiOperation(value = "添加新账户-ok", notes = "根据手机添加新账户，需要ticket(登陆获取)  "
            +"\nbody参数:\n" + "{\"accountAddress\": \"1\",\n" + "            \"accountDetail\": \"1\",\n" + "            \"accountName\": \"1\",\n" + "            \"accountNo\": \"1\",\n" +        "}"
            +"\nheader参数:ticket(登陆获取) eyJpZCI6IjMxNjNjYzY3Mzg0ZDRkNWViNmFmZThlMGZlMDJiYzlhIiwibG9naW5UaW1lIjoxNTU1Mjk4MTkwOTYwLCJwaG9uZSI6IjE1MzQ4OTA0MjI4Iiwic2lnbiI6Ijc4YTAyZWE0YzY2YWY4OTYxYjM3MWYwM2ZmMzM0OTYxIiwidXNlcm5hbWUiOiIxMjMifQ"
            , httpMethod = "POST")
    @ApiResponses(value =
            {@ApiResponse(code = 0, message = "", response = ResponseEntity.class)})
    @ApiImplicitParam(name = "ticket", value = "ticket", dataType = "String", paramType = "header",required = true)
    @PostMapping(value = "/account/save", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public Response<String> saveBank(@ApiIgnore @Current UserToken ticket,
                                     @RequestBody GameUserAccountModel gameUserAccountModel) {

        if(!ticket.getPhone().equals(gameUserAccountModel.getAccountNo())){
            return Response.buildError("账号与登录账户不一致" + gameUserAccountModel.getAccountNo());
        }
        GameUserAccount gameUserAccount = new GameUserAccount();
        try {
            gameUserAccount.setAccountNo(ticket.getPhone());
            gameUserAccount.setAccountAddress(gameUserAccountModel.getAccountAddress());
            gameUserAccount.setAccountDetail(gameUserAccountModel.getAccountDetail());
            gameUserAccount.setAccountName(gameUserAccountModel.getAccountName());
            gameUserAccount.setAccountType(gameUserAccountModel.getAccountType());
            gameUserAccount.setBankname(gameUserAccountModel.getBankname());
            //加入判断是否绑定,给出提示
            GameUserAccount dbAccount = gameUserAccountService.getAccount(gameUserAccount);
            if (!ObjectUtils.isEmpty(dbAccount)) {
                return Response.buildError("该帐户已绑定" + gameUserAccountModel.getAccountType());
            } else {
                gameUserAccountService.save(gameUserAccount);
                return Response.buildSuccess("添加成功");
            }
        } catch (Exception e) {
            log.error(RespErrorCodes.UNKNOWN_ERROR.errorCode(), e);
            return Response.buildError("系统异常,请稍后再试!");
        }
    }

    /**
     * 根据用户获取  该用户的上分下分机制  是否审核
     *
     * @param type  上分  1  下分 2  全部3
     * @param state 审核状态  0 待审核  1  审核通过  2审核拒绝  3 全部
     * @return
     */
    @SuppressWarnings("unchecked")
    @ApiOperation(value = "用户的上下分机制", notes = "获取该用户的上下分机制，是否审核需要传递ticket", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "ticket", value = "ticket", dataType = "String", paramType = "header",required = true),
            @ApiImplicitParam(name = "state", value = "审核状态  0 待审核  1  审核通过  2审核拒绝  3 全部", dataType = "String",required = true),
            @ApiImplicitParam(name = "type", value = "类型，上分  1  下分 2  全部3", dataType = "String",required = true)

    })
    @GetMapping(value = "/up/or/down/list", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public Response<List<UpAndDownReport>> upOrDownList(
            @ApiIgnore @Current UserToken userToken,
            @RequestParam("state") String state,
            @RequestParam("type") String type) {
        UpAndDownReport report = new UpAndDownReport();
        if (!"3".equals(type)) {
            report.setApplyType(type);
        }
        if (!"3".equals(state)) {
            report.setStatus(state);
        }
        report.setGameuserId(userToken.getId());
        try {
            List<UpAndDownReport> list = upAndDownReportService.findList(report);
            return Response.build(list);
        } catch (Exception e) {
            log.error(RespErrorCodes.UNKNOWN_ERROR.errorCode(), e);
            return Response.buildError("系统异常,请稍后再试!");
        }
    }


    /**
     * 修改用户的在线状态
     *
     * @param request
     * @return
     */
    @SuppressWarnings("unchecked")
    @ApiOperation(value = "更新用户在线状态", notes = "更新用户在线状态，需要ticket", httpMethod = "POST")
    @ApiImplicitParam(name = "ticket", value = "ticket", dataType = "String", paramType = "header",required = true)
    @PostMapping(value = "/update/online/status", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    @ResponseBody
    public Response<String> updateUserOnlineStatus(@ApiIgnore @Current UserToken userToken,
                                                   @ApiParam(name = "更新用户在线请求", value = "传入json格式", required = true)
                                                   @RequestBody UpdateUserOnlineRequest request) {
        try {
            int num = gameUserService.updateUserOnlineStatus(request.getUserOnlineStatus(), userToken.getId());
            if (num > 0) {
                return Response.buildSuccess("修改状态成功!");
            } else {
                return Response.buildError("修改状态失败");
            }
        } catch (Exception e) {
            log.error(RespErrorCodes.UNKNOWN_ERROR.errorCode(), e);
            return Response.buildError("系统异常,请稍后再试!");
        }

    }

    /**
     * 验证支付密码是否正确`
     *
     * @param request
     * @return
     */
    @SuppressWarnings("unchecked")
    @ApiOperation(value = "验证支付密码-ok", notes = "验证支付密码，需要ticket", httpMethod = "POST")
    @ApiResponses(value = {@ApiResponse(code = 0, message = "", response = ResponseEntity.class)})
    @ApiImplicitParam(name = "ticket", value = "ticket", dataType = "String", paramType = "header",required = true)
    @PostMapping(value = "/pay/password/check", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    @ResponseBody
    public Response regNewPayPwd(@ApiIgnore @Current UserToken ticket,
                                 @ApiParam(name = "验证支付密码请求", value = "传入json格式", required = true)
                                 @RequestBody VerifyPayPwdRequest request) {

        try {
            boolean result = gameUserService.regNewPayPwd(ticket.getId(), ticket.getUsername(), request.getUserPayPwd());
            //验证密码不传递消息
            //sendMessageSxfenCont();
            if (result) {
                return Response.buildSuccess("支付密码验证成功！");
            } else {
                return Response.buildError("支付密码错误！");
            }
        } catch (Exception e) {
            log.error(RespErrorCodes.UNKNOWN_ERROR.errorCode(), e);
            return Response.buildError("系统繁忙,请稍后再试!");
        }
    }

    /**
     * 充值提现消息传递
     *
     * @return
     */
    private Boolean sendMessageSxfenCont() throws IOException {
        UpAndDownReport upAndDownReport = new UpAndDownReport();
        upAndDownReport.setStatus("0");
        //应该为零
        int count = this.upAndDownReportService.findList(upAndDownReport).size();
        //sys_sxfen_count，得到集合
        Set<String> userIds = onlineAppContext.getUserIds(GameConstants.SYS_MSG_SXFEN_COUNT);

        Map<String, Object> map = new HashMap<>(16);
        map.put("count", count);
        String sendMsg = JSON.toJSONString(map);
        if (!CollectionUtils.isEmpty(userIds)) {
            userIds.forEach(userId -> {
                webSocketService.sendToTheUser(sendMsg, userId, GameConstants.SYS_MSG_SXFEN_COUNT,null);
            });
            return true;
        }
        return false;

    }
}
